﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_OCF_Parser.h".
//-------------------------------------------------------------------

#ifdef __UX_STL_UNIT_TEST__

#define UX_LIBARCHIVE_DISABLE
#define UX_ZLIB_DISABLE

#include "../ux_ocf_parser.h"

using namespace UX_STL;
using namespace UXParser;
using namespace UXMath;



struct TTestObject2
{
	string	sName;
	float	a, b;
	int		i;
	///
	TTestObject2(): a(0.f), b(0.f), i(0) {}
};


struct TTestObject
{
	variant_array_t			va_field;
	array< TTestObject2 >	array_field;
	int32_array_t			array_field2;
	binary_array_t			struct_field;
	fvec3					vec3_field1,
							vec3_field2;
	TTestObject2			obj_field1,
							obj_field2;
	string					string_field;
	string_array_t			str_arr_field;
};


static CMetaClass	s_cTestObject,
					s_cTestObject2;


UX_CREATE_META_OBJECT( TTestObject2, s_cTestObject2 );
UX_CREATE_META_OBJECT( TTestObject,  s_cTestObject );


void Test0()
{
	CConfig				c_cfg;
	CConfigContainerPtr	p_config;
	CMetaAddIteratorPtr	iter;
	TTestObject2		s_to2;
	TTestObject			s_to;
	static_obj_tree_t	s_tree;
	
	CMetaClass::s_InitBaseTypes();

	s_cTestObject2.CreateExt<TTestObject2>( "TestObject2" );
	iter = s_cTestObject2.GetAddIter( s_to2 );
	iter->AddField( s_to2.sName,		"name" );
	iter->AddField( s_to2.a,			"a" );
	iter->AddField( s_to2.b,			"b" );
	iter->AddField( s_to2.i,			"i" );

	s_cTestObject.CreateExt<TTestObject>( "TestObject" );
	iter = s_cTestObject.GetAddIter( s_to );
	iter->AddField( s_to.array_field,	"array_field" );
	iter->AddField( s_to.array_field2,	"array_field2" );
	iter->AddField( s_to.obj_field1,	"obj_field1" );
	iter->AddField( s_to.obj_field2,	"obj_field2" );
	iter->AddField( s_to.vec3_field1,	"vec3_field1" );
	iter->AddField( s_to.vec3_field2,	"vec3_field2" );
	iter->AddField( s_to.string_field,	"string_field" );
	iter->AddField( s_to.struct_field,	"struct_field" );
	iter->AddField( s_to.va_field,		"va_field" );
	iter->AddField( s_to.str_arr_field,	"str_arr_field" );


	c_cfg.SaveParsedFiles( true );
	c_cfg.SetParsedFilesDirectory( "../../Tests/" );
	c_cfg.Parse( "../../Tests/test.ocf", p_config.ref() );
	
	s_tree.First().PushBack( TConfigObjInfo( s_cTestObject.GetSetIter( s_to ), "test_object" ) );

	p_config->Process( s_tree.First() );

	WARNING( s_to.string_field.cstr() );
}


struct TestObj1
{
	int		i;
	float	f;

	TestObj1 () : i(0), f(0) {}

	virtual int VF ()	{ return 0; }
};

struct TestObj2 : TestObj1
{
	double	d;

	TestObj2 () : d(0) {}

	virtual int VF ()	{ return i; }
};

struct TestObj3
{
	TestObj1	to1;
	TestObj2	to2;

	virtual int VF ()	{ return 1111; }
	virtual float VF2 () { return to1.f; }
};

struct TObj0
{
	//float	f;
	int		i;
	fvec2	v;
	///
	TObj0 () :/* f(0),*/ i(0) {}
};

struct TObj1
{
	//float	f1;
	//double	d1;
	int		i1;
	TObj0	o0;
	///
	TObj1 () : /*d1(0), f1(0),*/ i1(0) {}
};

struct TObj2
{
	//char	c[13];
	//float	f2;
	int		i2;
	TObj1	o1;
	///
	TObj2 () : /*f2(0),*/ i2(0) { /*ZeroMem( c );*/ }
};



static CMetaClass	metaTestObj1,
					metaTestObj2,
					metaTestObj3;

UX_CREATE_META_OBJECT( TestObj1, metaTestObj1 );
UX_CREATE_META_OBJECT( TestObj2, metaTestObj2 );
UX_CREATE_META_OBJECT( TestObj3, metaTestObj3 );


static CMetaClass	metaTObj0,
					metaTObj1,
					metaTObj2;

UX_CREATE_META_OBJECT( TObj0, metaTObj0 );
UX_CREATE_META_OBJECT( TObj1, metaTObj1 );
UX_CREATE_META_OBJECT( TObj2, metaTObj1 );


void Test1 ()
{
	// initialization
	{
		CMetaClass::s_InitBaseTypes();

		CMetaAddIteratorPtr	iter;

		TestObj1	to1;
		TestObj2	to2;
		TestObj3	to3;

		metaTestObj1.CreateExt( "TestObj1", to1 );
		iter = metaTestObj1.GetAddIter( to1 );

		iter->AddField( to1.i,	"i" );
		iter->AddField( to1.f,	"f" );


		metaTestObj2.CreateExt( "TestObj2", to2 );
		metaTestObj2.Inherit( metaTestObj1 );
		iter = metaTestObj2.GetAddIter( to2 );

		iter->AddField( to2.d,	"d" );


		metaTestObj3.CreateExt( "TestObj3", to3 );
		//metaTestObj3.Inherit( metaTestObj1 );
		iter = metaTestObj3.GetAddIter( to3 );

		iter->AddField( to3.to1,	"to1" );
		iter->AddField( to3.to2,	"to2" );


		TObj0	o0;
		TObj1	o1;
		TObj2	o2;

		metaTObj0.CreateExt( "TObj0", o0 );
		iter = metaTObj0.GetAddIter( o0 );

		iter->AddField( o0.i,	"i" );
		iter->AddField( o0.v,	"v" );

		metaTObj1.CreateExt( "TObj1", o1 );
		iter = metaTObj1.GetAddIter( o1 );

		iter->AddField( o1.i1,	"i1" );
		iter->AddField( o1.o0,	"o0" );

		metaTObj2.CreateExt( "TObj2", o2 );
		iter = metaTObj2.GetAddIter( o2 );

		iter->AddField( o2.i2,	"i2" );
		iter->AddField( o2.o1,	"o1" );
	}


	// test 1
	CMetaSetIteratorPtr	iter;
		
	TestObj2	to2;

	iter = metaTestObj2.GetSetIter( to2 );

	int i = 1;
	float f = 0.12345f;
	double d = 12345.98765412;
	bool res;

	res = iter->SetValue( "i", &i, e_value::INT32 );		ASSERT( res );
	res = iter->SetValue( "f", &f, e_value::FLOAT );		ASSERT( res );
	res = iter->SetValue( "d", &d, e_value::DOUBLE );		ASSERT( res );

	ASSERT( to2.i == i );
	ASSERT( to2.f == f );
	ASSERT( to2.d == d );
	

	// test 2
	/*TestObj4	to4;

	iter = metaTestObj3.GetSetIter( to4.o );

	CMetaSetIteratorPtr	iter1 = new CMetaSetIterator( *iter, true );
	res = iter1->FindObject( "to1" );	ASSERT( res );

	CMetaSetIteratorPtr	iter2 = new CMetaSetIterator( *iter, true );
	res = iter2->FindObject( "to2" );	ASSERT( res );

	res = iter1->SetValue( "i", &i, e_value::INT32 );		ASSERT( res );
	res = iter1->SetValue( "f", &f, e_value::FLOAT );		ASSERT( res );
	res = iter2->SetValue( "i", &i, e_value::INT32 );		ASSERT( res );
	res = iter2->SetValue( "f", &f, e_value::FLOAT );		ASSERT( res );
	res = iter2->SetValue( "d", &d, e_value::DOUBLE );		ASSERT( res );
	//res = iter->SetValue( "i", &i, e_value::INT32 );		ASSERT( res );
	//res = iter->SetValue( "f", &f, e_value::FLOAT );		ASSERT( res );
	//res = iter->SetValue( "d", &d, e_value::DOUBLE );		ASSERT( res );*/


	// test 3
	TObj2	o2;

	uint8 *	o2_ptr	= (uint8 *) &o2;
	uint8 *	o1_ptr	= (uint8 *) &o2.o1;
	uint8 *	o0_ptr	= (uint8 *) &o2.o1.o0;
	uint8 *	v_ptr	= (uint8 *) &o2.o1.o0.v;
	
	usize	o2_o1	= o1_ptr - o2_ptr;
	usize	o2_o0	= o0_ptr - o2_ptr;
	usize	o2_v	= v_ptr  - o2_ptr;

	iter = metaTObj2.GetSetIter( o2 );

	CMetaSetIteratorPtr	iter1 = new CMetaSetIterator( *iter, true );

	CMetaSetIteratorPtr iter2 = new CMetaSetIterator( *iter, true );
	res = iter2->FindObject( "o1" );		ASSERT( res );
	ASSERT( iter2->GetObjPtrWithOffset() == o1_ptr );
	
	CMetaSetIteratorPtr iter3 = new CMetaSetIterator( *iter2, true );
	res = iter3->FindObject( "o0" );		ASSERT( res );
	res = iter1->FindObject( "o1.o0" );		ASSERT( res );
	ASSERT( iter1->GetObjPtrWithOffset() == iter3->GetObjPtrWithOffset() );
	ASSERT( iter1->GetObjPtrWithOffset() == o0_ptr );
	ASSERT( iter3->GetObjPtrWithOffset() == o0_ptr );
	
	CMetaSetIteratorPtr iter4 = new CMetaSetIterator( *iter3, true );
	res = iter4->FindObject( "v" );			ASSERT( res );
	res = iter1->FindObject( "o1.o0.v" );	ASSERT( res );
	ASSERT( iter1->GetObjPtrWithOffset() == iter4->GetObjPtrWithOffset() );
	ASSERT( iter1->GetObjPtrWithOffset() == v_ptr );
	ASSERT( iter4->GetObjPtrWithOffset() == v_ptr );

	res = iter1->SetValue( "x", &f, e_value::FLOAT );		ASSERT( res );
	ASSERT( o2.o1.o0.v.x == f );

	i = 1234;
	res = iter2->SetValue( "i1", &i, e_value::INT32 );		ASSERT( res );
	ASSERT( o2.o1.i1 == i );

	i = 5678;
	res = iter3->SetValue( "i", &i, e_value::INT32 );		ASSERT( res );
	ASSERT( o2.o1.o0.i == i );

	res = iter4->SetValue( "y", &f, e_value::FLOAT );		ASSERT( res );
	ASSERT( o2.o1.o0.v.y == f );
}


#include "../../stl_core/ux_stl_core_lib.h"
#include "../../stl_ext/ux_stl_ext_lib.h"

#ifdef PLATFORM_WINDOWS
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
#endif
{
	Test0();
	return 0;
}

#endif	__UX_STL_UNIT_TEST__